package com.terrapages.wmsc4j.layer;

import java.awt.Dimension;
import java.util.Iterator;
import java.util.NoSuchElementException;

import com.terrapages.wmsc4j.layer.WMSMetaLayer.MetaTile;
import com.terrapages.wmsc4j.layer.resolution.Resolution;

/**
 * Allows Meta Layers to be iterated over by the MetaTiles.
 * @author mvivian
 */
public class MetaLayerIterable implements Iterable<MetaTile> {
	private transient int xIndex;
	private transient int yIndex;
	private transient int zoom = 0;
	
	private transient MetaTile min; 
	private transient MetaTile max;
	
	WMSMetaLayer layer;

	public MetaLayerIterable(WMSMetaLayer layer) {
		this.layer = layer;
	}

	public Iterator<MetaTile> iterator() {
		return new MetaLayerIterator();
	}
	
	private class MetaLayerIterator implements Iterator<MetaTile> 
	{
		
		public MetaLayerIterator() {
			min = getMinimumMetaTile(layer.getResolutions().elementAt(zoom));
			max = getMaximumMetaTile(layer.getResolutions().elementAt(zoom));
			
			xIndex = min.getXIndex();
			yIndex = min.getYIndex();
			zoom = 0;
		}
		
		
		public boolean hasNext() {
			// TODO Auto-generated method stub
			return zoom < layer.getResolutions().size();
		}
		
		public MetaTile next() {
			if(!hasNext())
			{
				throw new NoSuchElementException();
			}
			
			final MetaTile metaTile = layer.new MetaTile(layer, layer.getZoomLevel(layer.getResolutions().elementAt(zoom)), xIndex, yIndex);
			
			xIndex++;
			if (xIndex>max.getXIndex())
			{
				yIndex++;
				if(yIndex > max.getYIndex())
				{
					zoom++;
					if(hasNext())
					{
						min = getMinimumMetaTile(layer.getResolutions().elementAt(zoom));
						max = getMaximumMetaTile(layer.getResolutions().elementAt(zoom));
					}
					yIndex = min.getYIndex();
				}
				xIndex = min.getXIndex();
			}
			
			
			return metaTile;
		}
		
		public void remove() {
			throw new UnsupportedOperationException("You cant remove tiles from a layer");
		}
		
		
		/**
		 * Gets the most South Western tile in the coverage at the given resolution.
		 * 
		 * @param resolution
		 * @return Tile
		 */
		private MetaTile getMinimumMetaTile(final Resolution resolution)
		{
			Dimension tileSize = new Dimension(layer.getFormat().getTileSize().width* layer.getMultiplicity(),layer.getFormat().getTileSize().height * layer.getMultiplicity());
			int xIndex=(int)((layer.getCoverage().getMinLongitude() - layer.getOrigin().getLongitude()) / ( resolution.getValue() * tileSize.getWidth()));
			int yIndex=(int)((layer.getCoverage().getMinLatitude() - layer.getOrigin().getLatitude()) / ( resolution.getValue() * tileSize.getHeight()));
			int zoom = layer.getZoomLevel(resolution);
			return layer.new MetaTile(layer,zoom,xIndex,yIndex);
		}
		
		/**
		 * Gets the most North Eastern tile in the coverage at the given resolution.
		 * 
		 * @param resolution
		 * @return Tile
		 */
		private MetaTile getMaximumMetaTile(final Resolution resolution)
		{
			Dimension tileSize = new Dimension(layer.getFormat().getTileSize().width* layer.getMultiplicity(),layer.getFormat().getTileSize().height * layer.getMultiplicity());
			int xIndex=(int)((layer.getCoverage().getMaxLongitude() - layer.getOrigin().getLongitude()) / ( resolution.getValue() * tileSize.getWidth())  - 0.0000001);
			int yIndex=(int)((layer.getCoverage().getMaxLatitude() - layer.getOrigin().getLatitude()) / ( resolution.getValue() * tileSize.getHeight())  - 0.0000001);
			int zoom = layer.getZoomLevel(resolution);
			return layer.new MetaTile(layer,zoom,xIndex,yIndex);
		}
	}
}

